package com.yuju.util;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

public class Utils {
	public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();
	private static HanyuPinyinOutputFormat format = null;
	static {
		format = new HanyuPinyinOutputFormat();
		format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
	}
	
	private static final char[] digitSource = new char[] { 
		'0','1','2','3','4','5','6','7','8','9'
	};
	private static final char[] charSource = new char[] {
		'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
		'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
		'u', 'v', 'w', 'x', 'y', 'z'
	};

	/**
	 * 用于随机生成验证码的数据源
	 */
	private static final char[] source = new char[] {

	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',

	'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',

	'U', 'V', 'W', 'X', 'Y', 'Z',

	'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'

	};

	/**
	 * 用于随机生成验证码的数据源
	 */
	private static final char[] sourceLower = new char[] {

	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',

	'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',

	'u', 'v', 'w', 'x', 'y', 'z',

	'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'

	};

	// 转换单个字符
	public static String convertCharacterToPinYin(char c) {
		String[] pinyin = null;
		try {
			pinyin = PinyinHelper.toHanyuPinyinStringArray(c, format);
		} catch (BadHanyuPinyinOutputFormatCombination e) {
			e.printStackTrace();
		}
		// 如果c不是汉字，toHanyuPinyinStringArray会返回null
		if (pinyin == null)
			return null;
		// 只取一个发音，如果是多音字，仅取第一个发音
		return pinyin[0];
	}

	// 转换一个字符串
	public static String convertStringToPinYin(String str) {
		StringBuilder sb = new StringBuilder();
		String tempPinyin = null;
		for (int i = 0; i < str.length(); ++i) {
			tempPinyin = convertCharacterToPinYin(str.charAt(i));
			if (tempPinyin == null) {
				// 如果str.charAt(i)非汉字，则保持原样
				sb.append(str.charAt(i));
			} else {
				sb.append(tempPinyin);
			}
		}
		return sb.toString();
	}

	public static String getUUID() {
		return UUID.randomUUID().toString().replace("-", "");
	}

	/**
	 * 格式化字符串
	 * 
	 * @param ids
	 *            以","分割的字符串:1,2
	 * @return 返回的字符串由单引号和逗号组成的字符串:'1','2'
	 */
	public static String formatIds(String ids) {
		String[] idsArr = ids.split(",");
		StringBuffer idsSb = new StringBuffer();
		for (int i = 0; i < idsArr.length; i++) {
			idsSb.append("'").append(idsArr[i]).append("'").append(",");
		}
		return idsSb.delete(idsSb.length() - 1, idsSb.length()).toString();
	}

	/**
	 * 判断一个对象是否为空
	 * 
	 * @param obj
	 *            任意对象
	 * @return true/false
	 */
	public static boolean isNotNull(Object obj) {
		return obj != null && !"".equals(obj.toString())
				&& !"null".equals(obj.toString())
				&& !"NULL".equals(obj.toString()) && !"undefined".equals(obj
				.toString());
	}

	/**
	 * 判断一个对象是否为空
	 * 
	 * @param obj
	 *            任意对象
	 * @return true/false
	 */
	public static boolean isNull(Object obj) {
		return !isNotNull(obj);
	}
	
	/**
	 * 判断是不是一个不为0的数字
	 * @param obj
	 * @return
	 */
	public static boolean isNot0Dig(Object obj) {
		if (isNotNull(obj))
			return !"0".equals(obj.toString()) && !"0.0".equals(obj.toString()) && !"0.00".equals(obj.toString());
		return false;
	}

	/**
	 * 生成随机数
	 * 
	 * @param charCount
	 *            位数
	 * @return 随机数
	 */
	public static String getRandNum(int charCount) {
		String charValue = "";
		for (int i = 0; i < charCount; i++) {
			char c = (char) (randomInt(0, 10) + '0');
			charValue += String.valueOf(c);
		}
		return charValue;
	}

	public static int randomInt(int from, int to) {
		Random r = new Random();
		return from + r.nextInt(to - from);
	}

	/**
	 * 生成随机字符串
	 */
	public static String getRandomText() {
		Random r = new Random();
		char[] sourcec = new char[6];

		for (int i = 0; i < sourcec.length; i++) {

			sourcec[i] = sourceLower[r.nextInt(source.length)];

		}

		return new String(sourcec);
	}

	/**
	 * 生成随机字符串
	 */
	public static String getRandomText(int len) {
		Random r = new Random();
		char[] sourcec = new char[len];

		for (int i = 0; i < sourcec.length; i++) {

			sourcec[i] = sourceLower[r.nextInt(source.length)];

		}

		return new String(sourcec);
	}
	
	/**
	 * 取得随机的字符-char数组
	 * @param len 生成随机数的长度
	 * @return 随机数
	 */
	public static char[] getCharArrRandom(int len) {
		Random r = new Random();
		char[] sourcec = new char[len];

		for (int i = 0; i < sourcec.length; i++) {

			sourcec[i] = charSource[r.nextInt(charSource.length)];

		}

		return sourcec;
	}

	/**
	 * 取得随机的字符
	 * @param len 生成随机数的长度
	 * @return 随机数
	 */
	public static String getCharRandom(int len) {
		Random r = new Random();
		char[] sourcec = new char[len];

		for (int i = 0; i < sourcec.length; i++) {

			sourcec[i] = charSource[r.nextInt(charSource.length)];

		}

		return new String(sourcec);
	}
	
	/**
	 * 取得纯数字随机数-char数组
	 * @param len 生成随机数的长度
	 * @return 随机数
	 */
	public static char[] getDigitArrRandom(int len) {
		Random r = new Random();
		char[] sourcec = new char[len];

		for (int i = 0; i < sourcec.length; i++) {

			sourcec[i] = digitSource[r.nextInt(digitSource.length)];

		}

		return sourcec;
	}
	
	/**
	 * 取得纯数字随机数
	 * @param len 生成随机数的长度
	 * @return 随机数
	 */
	public static String getDigitRandom(int len) {
		Random r = new Random();
		char[] sourcec = new char[len];

		for (int i = 0; i < sourcec.length; i++) {

			sourcec[i] = digitSource[r.nextInt(digitSource.length)];

		}

		return new String(sourcec);
	}
	
	/**
	 * 获取指定长度随机简体中文
	 * 
	 * @param len
	 *            int
	 * @return String
	 */
	public static String getRandomJianHan(int len) {
		String ret = "";
		for (int i = 0; i < len; i++) {
			String str = null;
			int hightPos, lowPos; // 定义高低位
			Random random = new Random();
			hightPos = (176 + Math.abs(random.nextInt(39))); // 获取高位值
			lowPos = (161 + Math.abs(random.nextInt(93))); // 获取低位值
			byte[] b = new byte[2];
			b[0] = (new Integer(hightPos).byteValue());
			b[1] = (new Integer(lowPos).byteValue());
			try {
				str = new String(b, "GBk"); // 转成中文
			} catch (UnsupportedEncodingException ex) {
				ex.printStackTrace();
			}
			ret += str;
		}
		return ret;
	}
	

	/**
	 * 取得随机数字字符组合串
	 * @param len 随机字符串长度
	 * @return 随机字符串
	 */
	public static String getDC(int len) {
		int subLen = len / 2;
		
		// 生成随机纯数字
		char[] digitChars = getDigitArrRandom(subLen);
		
		// 生成随机纯字符
		char[] cchars = getCharArrRandom(subLen);
		
		char[] retChars = new char[len];

		// 将生成的随机纯数字拷贝到retChars
		System.arraycopy(digitChars, 0, retChars, 0, digitChars.length);
		System.arraycopy(cchars, 0, retChars, digitChars.length, cchars.length);
		
		if(len % 2 != 0) 
			retChars[retChars.length-1] = getCharArrRandom(1)[0];
		
		return new String(retChars);
	}
	
	public static String getDCC(int len) {
		int subLen = len / 3;
		
		// 生成随机纯数字
		char[] digitChars = getDigitArrRandom(subLen);
		
		// 生成随机纯字符
		char[] cchars = getCharArrRandom(subLen);
		
		// 生成随机汉字
		String chinese = getRandomJianHan(subLen);
		
		char[] cChars = chinese.toCharArray();

		char[] retChars = new char[len];

		// 将生成的随机纯数字拷贝到retChars
		System.arraycopy(digitChars, 0, retChars, 0, digitChars.length);
		System.arraycopy(cchars, 0, retChars, digitChars.length, cchars.length);
		System.arraycopy(cChars, 0, retChars, digitChars.length+cChars.length, cChars.length);

		if(len % 3 != 0) 
			retChars[retChars.length-1] = getCharArrRandom(1)[0];
		
		return new String(retChars);
	}

	static {
		getAllFileType(); // 初始化文件类型信息
	}

	/**
	 * 常见文件头信息
	 */
	private static void getAllFileType() {
		FILE_TYPE_MAP.put("jpg", "FFD8FF"); // JPEG (jpg)
		FILE_TYPE_MAP.put("png", "89504E47"); // PNG (png)
		FILE_TYPE_MAP.put("gif", "47494638"); // GIF (gif)
		FILE_TYPE_MAP.put("tif", "49492A00"); // TIFF (tif)
		FILE_TYPE_MAP.put("bmp", "424D"); // Windows Bitmap (bmp)
		FILE_TYPE_MAP.put("dwg", "41433130"); // CAD (dwg)
		FILE_TYPE_MAP.put("html", "68746D6C3E"); // HTML (html)
		FILE_TYPE_MAP.put("rtf", "7B5C727466"); // Rich Text Format (rtf)
		FILE_TYPE_MAP.put("xml", "3C3F786D6C");
		FILE_TYPE_MAP.put("zip", "504B0304");
		FILE_TYPE_MAP.put("rar", "52617221");
		FILE_TYPE_MAP.put("psd", "38425053"); // Photoshop (psd)
		FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A"); // Email
																	// [thorough
																	// only]
																	// (eml)
		FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F"); // Outlook Express (dbx)
		FILE_TYPE_MAP.put("pst", "2142444E"); // Outlook (pst)
		FILE_TYPE_MAP.put("xls", "D0CF11E0"); // MS Word
		FILE_TYPE_MAP.put("doc", "D0CF11E0"); // MS Excel 注意：word 和 excel的文件头一样
		FILE_TYPE_MAP.put("mdb", "5374616E64617264204A"); // MS Access (mdb)
		FILE_TYPE_MAP.put("wpd", "FF575043"); // WordPerfect (wpd)
		FILE_TYPE_MAP.put("eps", "252150532D41646F6265");
		FILE_TYPE_MAP.put("ps", "252150532D41646F6265");
		FILE_TYPE_MAP.put("pdf", "255044462D312E"); // Adobe Acrobat (pdf)
		FILE_TYPE_MAP.put("qdf", "AC9EBD8F"); // Quicken (qdf)
		FILE_TYPE_MAP.put("pwl", "E3828596"); // Windows Password (pwl)
		FILE_TYPE_MAP.put("wav", "57415645"); // Wave (wav)
		FILE_TYPE_MAP.put("avi", "41564920");
		FILE_TYPE_MAP.put("ram", "2E7261FD"); // Real Audio (ram)
		FILE_TYPE_MAP.put("rm", "2E524D46"); // Real Media (rm)
		FILE_TYPE_MAP.put("mpg", "000001BA"); //
		FILE_TYPE_MAP.put("mov", "6D6F6F76"); // Quicktime (mov)
		FILE_TYPE_MAP.put("asf", "3026B2758E66CF11"); // Windows Media (asf)
		FILE_TYPE_MAP.put("mid", "4D546864"); // MIDI (mid)
	}

	/**
	 * 获取图片文件实际类型,若不是图片则返回null
	 * 
	 * @param File
	 * @return fileType
	 */
	public final static String getImageFileType(File f) {
		if (isImage(f)) {
			try {
				ImageInputStream iis = ImageIO.createImageInputStream(f);
				Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
				if (!iter.hasNext()) {
					return null;
				}
				ImageReader reader = iter.next();
				iis.close();
				return reader.getFormatName();
			} catch (IOException e) {
				return null;
			} catch (Exception e) {
				return null;
			}
		}
		return null;
	}

	/**
	 * 获取图片文件实际类型,若不是图片则返回null
	 * 
	 * @param File
	 * @return fileType
	 */
	public final static String getImageFileType(InputStream inputStream) {
		if (isImage(inputStream)) {
			try {
				Iterator<ImageReader> iter = ImageIO.getImageReaders(inputStream);
				if (!iter.hasNext()) {
					return null;
				}
				ImageReader reader = iter.next();
				return reader.getFormatName();
			} catch (IOException e) {
				return null;
			} catch (Exception e) {
				return null;
			}
		}
		return null;
	}

	/**
	 * 获取文件类型,包括图片,若格式不是已配置的,则返回null
	 * 
	 * @param file
	 * @return fileType
	 */
	public final static String getFileByFile(File file) {
		String filetype = null;
		byte[] b = new byte[50];
		try {
			InputStream is = new FileInputStream(file);
			is.read(b);
			filetype = getFileTypeByStream(b);
			is.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return filetype;
	}

	/**
	 * 获取文件类型,包括图片,若格式不是已配置的,则返回null
	 * 
	 * @param file
	 * @return fileType
	 */
	public final static String getFileByFile(InputStream is) {
		String filetype = null;
		byte[] b = new byte[50];
		try {
			is.read(b);
			filetype = getFileTypeByStream(b);
			is.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return filetype;
	}

	/**
	 * 根据文件流获取文件的类型
	 * 
	 * @param b
	 * @return fileType
	 */
	public final static String getFileTypeByStream(byte[] b) {
		String filetypeHex = String.valueOf(getFileHexString(b));
		Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP
				.entrySet().iterator();
		while (entryiterator.hasNext()) {
			Entry<String, String> entry = entryiterator.next();
			String fileTypeHexValue = entry.getValue();
			if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
				return entry.getKey();
			}
		}
		return null;
	}

	/**
	 * 判断文件是否为图片
	 * 
	 * @param file
	 * @return true 是 | false 否
	 */
	public static final boolean isImage(File file) {
		boolean flag = false;
		try {
			BufferedImage bufreader = ImageIO.read(file);
			int width = bufreader.getWidth();
			int height = bufreader.getHeight();
			if (width == 0 || height == 0) {
				flag = false;
			} else {
				flag = true;
			}
		} catch (IOException e) {
			flag = false;
		} catch (Exception e) {
			flag = false;
		}
		return flag;
	}

	/**
	 * 判断文件是否为图片
	 * 
	 * @param file
	 * @return true 是 | false 否
	 */
	public static final boolean isImage(InputStream inputStream) {
		boolean flag = false;
		try {
			BufferedImage bufreader = ImageIO.read(inputStream);
			int width = bufreader.getWidth();
			int height = bufreader.getHeight();
			if (width == 0 || height == 0) {
				flag = false;
			} else {
				flag = true;
			}
		} catch (IOException e) {
			flag = false;
		} catch (Exception e) {
			flag = false;
		}
		return flag;
	}

	/**
	 * 获取文件的十六进制
	 * 
	 * @param b
	 * @return fileTypeHex
	 */
	public final static String getFileHexString(byte[] b) {
		StringBuilder stringBuilder = new StringBuilder();
		if (b == null || b.length <= 0) {
			return null;
		}
		for (int i = 0; i < b.length; i++) {
			int v = b[i] & 0xFF;
			String hv = Integer.toHexString(v);
			if (hv.length() < 2) {
				stringBuilder.append(0);
			}
			stringBuilder.append(hv);
		}
		return stringBuilder.toString();
	}

	/**
	 * 获取MD5加密字符串
	 * 
	 * @param strSrc
	 *            源字符串
	 * @return MD5加密字符串
	 */
	public static String MD5(String strSrc) {
		// parameter strSrc is a string will be encrypted,
		// parameter encName is the algorithm name will be used.
		// encName dafault to "MD5"
		// 得到MessageDigest对象
		// 加密后的字符串
		String strDes = null;
		// 要加密的字符串字节型数组
		byte[] bt = strSrc.getBytes();
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(bt);
			// 通过执行诸如填充之类的最终操作完成哈希计算
			strDes = bytes2Hex(md.digest()); // to HexString
		} catch (NoSuchAlgorithmException e) {
			System.out.println("Invalid algorithm./n" + e.getMessage());
			return null;
		}
		return strDes;
	}

	// 将字节数组转换成16进制的字符串
	private static String bytes2Hex(byte[] bts) {
		String des = "";
		String tmp = null;

		for (int i = 0; i < bts.length; i++) {
			tmp = (Integer.toHexString(bts[i] & 0xFF));
			if (tmp.length() == 1) {
				des += "0";
			}
			des += tmp;
		}
		return des;
	}
	
	/**
	 * SHA-1加密
	 * @author xue
	 * @date 2016-09-04
	 * @param str 被加密字符串
	 * @return String 已加密字符串
	 */
	public static String SHA1(String str) {
		try {
			// get SHA-1 instance
			MessageDigest digest = MessageDigest.getInstance("SHA-1");
			digest.update(str.getBytes());
			// 获取字节数组
			byte[] messageDigest = digest.digest();
			// Create Hex String
			StringBuffer hexString = new StringBuffer();
			// 字节数组转换为 十六进制数 
			for (int i=0; i<messageDigest.length; i++) {
				String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
				if (shaHex.length() < 2) {
					hexString.append(0);
				}
				hexString.append(shaHex);
			}
			
			return hexString.toString();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 获取参数的字典排序
	 * @param maps 参数key-value map集合
	 * @return String 排序后的字符串
	 */
	public static String getOrderByLexicographic(Map<String, Object> maps) {
		return splitParams(lexicographicOrder(getParamsName(maps)), maps);
	}
	
	/**
	 * 参数名称 key
	 * @param maps 参数key-value map集合
	 * @return
	 */
	public static List<String> getParamsName(Map<String, Object> maps) {
		List<String> paramNames = new ArrayList<String>();
		for (Map.Entry<String, Object> entry : maps.entrySet()) {
			paramNames.add(entry.getKey());
		}
		return paramNames;
	}
	
	/**
	 * 参数名称按字典排序	
	 * @author xue
	 * @date 2016-09-04
	 * @param paramNames 参数名称集合
	 * @return List 排序好的参数集合
	 */
	public static List<String> lexicographicOrder(List<String> paramNames) {
		Collections.sort(paramNames);
		return paramNames;
	}
	
	/**
	 * 拼接排序好的参数名称和参数值
	 * @author xue
	 * @date 2016-09-04
	 * @param paramNames 排序后的参数名称集合
	 * @param maps 参数key-value map集合
	 * @return String 拼接后的字符串
	 */
	public static String splitParams(List<String> paramNames, Map<String, Object> maps) {
		StringBuilder paramStr = new StringBuilder();
		for (String paramName : paramNames) {
			paramStr.append(paramName);
			for (Map.Entry<String, Object> entry : maps.entrySet()) {
				if (paramName.equals(entry.getKey())) {
					paramStr.append(String.valueOf(entry.getValue()));
				}
			}
		}
		return paramStr.toString();
	}

	/**
	 * 验证手机号码
	 * 
	 * @param mobiles
	 * @return
	 */
	public static boolean isMobileNumber(String mobileNumber) {
		boolean flag = false;
		try {
			Pattern regex = Pattern
					.compile("^(((13[0-9])|(15([0-9]))|(17[0-9])|(18[0-9]))\\d{8})|(0\\d{2}-\\d{8})|(0\\d{3}-\\d{7})$");
			// "^(((13[0-9])|(15([0-3]|[5-9]))|(17[0-9])|(18[0,1,5-9]))\\d{8})|(0\\d{2}-\\d{8})|(0\\d{3}-\\d{7})$"
			Matcher matcher = regex.matcher(mobileNumber);
			flag = matcher.matches();
		} catch (Exception e) {
			flag = false;
		}
		return flag;
	}

	/**
	 * 批量验证手机号码以,号分隔,其中有一个手机号有误则返回FALSE
	 * 
	 * @param mobiles
	 * @return
	 */
	public static boolean isMobileNumbers(String mobileNumbers) {
		boolean flag = true;
		String[] mobiles = mobileNumbers.split(",");
		for (int i = 0; i < mobiles.length; i++) {
			boolean _flag = isMobileNumber(mobiles[i]);
			if (_flag == false)
				flag = false;

		}
		return flag;
	}
	
	/**
	 * 检查字符串是否匹配指定的模式
	 * @author xue
	 * @since 2016-02-24
	 * @update 2016-02-24
	 * @param pattern 模式，正则表达式
	 * @param str 字符串
	 * @return 匹配则返回true，否则返回false
	 */
	public static boolean isMatch(String pattern, String str) {
		if(isNull(pattern))
			return false;
		
		if(isNull(str))
			return false;
		
		Pattern r = Pattern.compile(pattern);
		
		Matcher m = r.matcher(str);
		
		return m.find();
	}
	
	/**
	 * 身份验证token值算法：
	 * 算法是：将特定的某几个参数一map的数据结构传入，
	 * 进行字典序排序以后进行md5加密,32位小写加密；
	 * @author xue
	 * @date 2016-12-11
	 * @param params 约定用来计算token的参数
	 * @return 加密后的token
	 */
	public static String authentication(Map<String , Object> params) throws RuntimeException {
		//排序，根据keyde 字典序排序
		if(null == params){
			throw new RuntimeException("传入参数为空");
		}
		List<Map.Entry<String,Object>> list = new ArrayList<Map.Entry<String,Object>>(params.entrySet());
		Collections.sort(list, new Comparator<Map.Entry<String, Object>>(){
			//升序排序
			public int compare(Entry<String,Object> o1, Entry<String,Object> o2){
				return o1.getKey().compareTo(o2.getKey());
			}
		});
		
		StringBuffer srcSb = new StringBuffer();
		for(Map.Entry<String , Object>srcAtom : list){
			srcSb.append(String.valueOf(srcAtom.getValue()));
		}
		System.out.println("身份验证加密前字符串："+srcSb.toString());
		//计算token
		String token = Utils.MD5(srcSb.toString());
		return token;
	}
	
	/**
	 * 身份验证token值算法：
	 * 算法是：将特定的某几个参数一map的数据结构传入，
	 * 进行字典序排序以后进行md5加密,32位小写加密；
	 * @author xue
	 * @date 2016-12-11
	 * @param params 约定用来计算token的参数
	 * @param key 秘钥
	 * @return 加密后的token
	 */
	public static String authentication(Map<String , Object> params, String key) throws RuntimeException {
		//排序，根据keyde 字典序排序
		if(null == params){
			throw new RuntimeException("传入参数为空");
		}
		List<Map.Entry<String,Object>> list = new ArrayList<Map.Entry<String,Object>>(params.entrySet());
		Collections.sort(list, new Comparator<Map.Entry<String, Object>>(){
			//升序排序
			public int compare(Entry<String,Object> o1, Entry<String,Object> o2){
				return o1.getKey().compareTo(o2.getKey());
			}
		});
		
		StringBuffer srcSb = new StringBuffer();
		for(Map.Entry<String , Object>srcAtom : list){
			srcSb.append(String.valueOf(srcAtom.getValue()));
		}
		//AES加密token
		String token = AESUtil.AES_encrypt(srcSb.toString(), key);
		return token;
	}
	
	/**
	 * 身份验证token值算法：
	 * 算法是：将特定的某几个参数一map的数据结构传入，
	 * 进行字典序排序以后进行md5加密,32位小写加密；
	 * @author xue
	 * @date 2016-12-11
	 * @param params 约定用来计算token的参数
	 * @param key 秘钥
	 * @return 加密后的token
	 */
	public static String authentication(Map<String, Object> params, boolean isRandom, String key) throws RuntimeException {
		if (Utils.isNull(params)) {
			throw new RuntimeException("传入参数为空");
		}
		
		StringBuffer srcSb = new StringBuffer();
		Map<String, Object> map = getSortedMap(params, isRandom, null);
		for (Iterator<Entry<String, Object>> iter = map.entrySet().iterator(); iter.hasNext();) {
    		Entry<String, Object> iters = iter.next();
    		srcSb.append(String.valueOf(iters.getValue()));
    	}
		
		//AES加密token
		String token = AESUtil.AES_encrypt(srcSb.toString(), key);
		return token;
	}
	
	public static Map<String, Object> getSortedMap(Map<String, Object> map, boolean isRandom, boolean... isLastFixed) {
		Map<String, Object> resultTemporary = new LinkedHashMap<String, Object>();
		if (isRandom) { // 随机排序
			List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>(map.entrySet());
			// 最后一项不参加排序
			Map.Entry<String, Object> entryLast = list.get(list.size() - 1);
			if (isLastFixed != null && isLastFixed[0] == true) {// 最后一项固定则删除
				list.remove(list.size() - 1);
			}
			Collections.sort(list, new Comparator<Map.Entry<String, Object>>() {

				@Override
				public int compare(Entry<String, Object> o1, Entry<String, Object> o2) {
					int randomOne = (int) (Math.random() * 10);
					int randomTwo = (int) (Math.random() * 10);
					return randomOne - randomTwo;
				}
				
			});
			
			StringBuffer srcSb = new StringBuffer();
			for (int i=0; i<list.size(); i++) {
				Map.Entry<String, Object> mapEntry = list.get(i);
				resultTemporary.put(mapEntry.getKey(), mapEntry.getValue());
				srcSb.append(String.valueOf(list.get(i)));
			}
			if (isLastFixed != null && isLastFixed[0] == true) { // 最后一项固定，则重新添加
				resultTemporary.put(entryLast.getKey(), entryLast.getValue());
			}
			System.out.println(srcSb.toString());
		} else {
			// 字典排序
			List<Map.Entry<String,Object>> list = new ArrayList<Map.Entry<String,Object>>(map.entrySet());
			Collections.sort(list, new Comparator<Map.Entry<String, Object>>(){
				//升序排序
				public int compare(Entry<String,Object> o1, Entry<String,Object> o2){
					return o1.getKey().compareTo(o2.getKey());
				}
			});
			for (int i=0; i<list.size(); i++) {
				Map.Entry<String, Object> mapEntry = list.get(i);
				resultTemporary.put(mapEntry.getKey(), mapEntry.getValue());
			}
		}
		return resultTemporary;
	}
	
	/**
	 * 求地球两点距离
	 * @author xue
	 * @date 2016-11-23
	 * @param lat1 A点经度
	 * @param lng1 A点维度
	 * @param lat2 B点经度
	 * @param lng2 B点维度
	 */
	public static void calDis(String lat1, String lng1, String lat2, String lng2) {
		String v_lat1 = MathUtil.mul(lat1, "1");
		String v_lng1 = MathUtil.mul(lng1, "1");
		String v_lat2 = MathUtil.mul(lat2, "1");
		String v_lng2 = MathUtil.mul(lng2, "1");
		String dis =  getDistance(v_lat1, v_lng1, v_lat2, v_lng2);
		System.out.println(dis);
	}
	
	public static String getDistance(String lat1, String lng1, String lat2, String lng2) {
		if ((Math.abs(Double.valueOf(lat1)) > 90) || (Math.abs(Double.valueOf(lat2)) > 90 )) {
			return null;
		}
		if((Math.abs(Double.valueOf(lng1)) > 180) || (Math.abs(Double.valueOf(lng2)) > 180)) {
			return null;
		}
		
		String radLat1 = rad(lat1);
		String radLat2 = rad(lat2);
		String a = MathUtil.sub(radLat1, radLat2);
		String b = MathUtil.sub(rad(lng1), rad(lng2));
		double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(Double.valueOf(MathUtil.div(a,"2"))),2) +
				Math.cos(Double.valueOf(radLat1))*Math.cos(Double.valueOf(radLat2))*Math.pow(Math.sin(Double.valueOf(MathUtil.div(b,"2"))),2)));

		s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(Double.valueOf(MathUtil.div(a,"2"))),2) + 
				Math.cos(Double.valueOf(radLat1))*Math.cos(Double.valueOf(radLat2)) * Math.pow(Math.sin(Double.valueOf(MathUtil.div(b,"2"))),2)));
		
		s = s *6378.137 ;// EARTH_RADIUS;
		
        NumberFormat nf = NumberFormat.getNumberInstance();   
        nf.setMaximumFractionDigits(2);   
		// s = Math.round(s * 10000) / 10000;
		
		return nf.format(s);
	}
	
	private static String rad(String d) {
		return MathUtil.mul(d, String.valueOf(Math.PI / 180.0));
	}
	
	/**
	 * 参数过滤
	 * @author xue
	 * @date 2017-01-07
	 * */
	public static String filterParVal(String parVal) {
		if (Utils.isNull(parVal))
			return null;
		String reg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"  
	            + "(\\b(?i)(select | select|update | update|and | and|or | or|delete | delete|insert | insert|trancate|char | char|into | into|substr | substr|ascii|declare | declare|exec | exec|count| count|master|into|drop | drop|execute | execute)\\b)";
		return parVal.replaceAll(reg, "");
	}
	
	/**
	 * 功能：给in查询的字段加引号<br/>
	 *
	 * @author xue
	 * @param idsStr 原字符串，以“,”号隔开，如：1001,1002,1003
	 * @param prefix 前缀，即给分割的字符串前加字符，如：“'”
	 * @param sufix 后缀，即给分割的字符串后加字符，如：“'”
	 * @version 2017年4月8日 下午5:25:18 <br/>
	 */
	public static String getIds(String idsStr, String prefix, String sufix) {
		String[] ids = idsStr.split(",");
		StringBuffer sbSql = new StringBuffer();
		for (int i=0; i<ids.length; i++) {
			sbSql.append((prefix != null ? prefix : "") + Utils.filterParVal(ids[i]) + (sufix != null ? sufix : ""));
			if (i != ids.length - 1) {
				sbSql.append(",");
			}
		}
		return sbSql.toString();
	}

	public static void main(String[] args) throws Exception {
		/*
		 * File f = new File("/home/xue/Desktop/jhs.bmp"); if (f.exists()) {
		 * String filetype1 = getImageFileType(f);
		 * System.out.println(filetype1); String filetype2 = getFileByFile(f);
		 * System.out.println(filetype2); }000010 86561200f3f1f2bf5cd4218495323b3f
		 */
		System.out.println(isMobileNumber("13598990808"));
		System.out.println(Utils.MD5("123456"));
		System.out.println(getRandomText(8));
		System.out.println(convertStringToPinYin("包").toUpperCase());
		calDis("34.779126", "113.693733", "34.781584", "113.695117");
		System.out.println(MathUtil.compareTo("1", "2"));
		System.out.println(Utils.getUUID());
		/*
		 * return !(obj != null && !"".equals(obj.toString()) &&
		 * !"null".equals(obj.toString()) && !"NULL".equals(obj.toString()) &&
		 * !"undefined".equals(obj.toString()));
		 */
		// System.out.println(Utils.isNull(null));
	}

}
